<?php

class MSN {

    //Ha true a loop-ban Logout-ol
    public $kill_me = false;

    //Debug üzenetek megjelenítése
    public $debug = true;

    //Log file
    public $log_file = '';

    //A switchboard-ok tárolója
    private $switchboards = array();

    private $online     = false;

    private $aContactList   = array();
    public $contacts        = array();


    /* NEW */

    public $helper      = null;
    public $protocol    = null;
    public $connection  = null;
    public $timeout     = 15;

    public function __construct($timeout = 15)
    {

        $this->timeout = $timeout;
        // check support
        if (!function_exists('curl_init')) die("We need curl module!\n");
        if (!function_exists('preg_match')) die("We need pcre module!\n");

        $this->helper       = new msnHelper( &$this );
        $this->connection   = new MSN_Connection( &$this );
        $this->protocol     = new MSN_Protocol( &$this );
    }



    public function connect($user, $password)
    {
        $this->helper->log('Connection to MSN networks with: '.$user);
        $this->helper->user = $user;
        $this->helper->password = $password;

        $this->connection->init();
        $this->helper->authed = false;

        $start_ts = time();
        while ( !$this->connection->EOF() ) {
            $data = $this->connection->ReadLn();

            //Cant get any data
            if ($data === false) {
                if ( !$this->connection->handleTimeout( $start_ts, $this->timeout ) )
                    return false;

                continue;
            }

            $code = substr($data, 0, 3);
            $start_ts = time();

            switch ($code) {
                case 'VER':
                    $this->protocol->answerVER();
                    break;

                case 'CVR':
                    $this->protocol->answerCVR();
                    break;

                case 'GCF':
                    $this->protocol->answerGCF($data);
                    break;

                case 'USR':
                    if ( $this->protocol->answerUSR($data) && $this->helper->authed )
                        return true;                        
                    break;

                case 'XFR':
                    $this->protocol->answerXFR($data);
                    break;

                default:
                    // we'll quit if got any error
                    if (is_numeric($code)) {
                        $this->helper->logoutError( 'Error code: '.$code.', please check the detail information from: http://msnpiki.msnfanatic.com/index.php/Reference:Error_List' );
                        return false;
                    } else {
                         $this->helper->log("*** CIGNORE: ".$code.' | '.$data);
                    }
                    // unknown response from server, just ignore it
                    break;
            }
        }

        return false;
    }

    //Fő ciklus
    function doLoop( $aParams ) {
        $this->helper->log('*** Start Loop ***');

        $this->kill_me = false;

        $initFunction       = $aParams['initFunction'];
        $loopFunction       = $aParams['loopFunction'];

        //Loading contact list
        $this->aContactList = $this->helper->getMembershipList();

        foreach ( $this->aContactList as $domain=>$items ) {
            foreach ( $items as $address=>$val ) {
                $this->contacts[ $address.'@'.$domain ] = array();
            }
        }

        $this->protocol->sendADL( $this->aContactList );

        $this->online = true;
        if ($initFunction && function_exists($initFunction) && is_callable($initFunction))
            $initFunction($this);


        while ( 1 ) {
            if ($this->kill_me) {
                if ( is_resource($this->helper->server_connection) && !$this->helper->serverEOF() ) {
                    sleep(2);
                    $this->helper->logoutError('Someon tell me I need to kill myself');
                }
                break;
            }

            //Check Main Server Responses
            $data = $this->connection->readLn();


            if (!($data === false)) {
                $code = substr($data, 0, 3);
                switch ($code) {
                    case 'SBS': 
                        // after 'USR {id} OK {user} {verify} 0' response, the server will send SBS and profile to us
                        // NS: <<< SBS 0 null
                        $this->aContactList = $this->helper->getMembershipList();

                        foreach ( $this->aContactList as $domain=>$items ) {
                            foreach ( $items as $address=>$val ) {
                                $this->contacts[ $address.'@'.$domain ] = array();
                            }
                        }

                        $this->protocol->sendADL( $this->aContactList );

                        $this->online = true;
                        if ($initFunction && function_exists($initFunction) && is_callable($initFunction))
                            $initFunction($this);
                        break;

                    case 'RFS': 
                        $this->protocol->sendADL( $this->aContactList );
                        break;

                    case 'LST': 
                        $this->protocol->answerLST( $data, &$this->aContactList );
                        break;

                    case 'ADD': 
                        @list(/* ADD */, /* 0 */, $u_list, /* 0 */, $u_email, /* alias */) = @explode(' ', $data);
                        $this->helper->log( $u_email.' added me to their contact list' );
                        break;

                    case 'REM': 
                        @list(/* REM */, /* 0 */, $u_list, /* 0 */, $u_email,) = @explode(' ', $data);
                        $this->helper->log( $u_email.' removed me from their contact list' );
                        break;

                    case 'ADL': 
                        $this->helper->log( 'somebody added me to their contact list' );
                        break;

                    case 'RML': 
                        $this->helper->log( 'somebody removed me from their contact list' );
                        break;

                    case 'MSG': 
                        $this->protocol->answerMSG( $data );
                        break;

                    case 'UBM': 
                        break;

                    case 'UBX': 
                        $this->protocol->answerUBX( $data );
                        break;

                    case 'CHL': 
                        $this->protocol->answerCHL( $data );
                        break;

                    case 'CHG': 
                        break;

                    case 'XFR': 
                        break;

                    case 'QNG': 
                        break;

                    case 'RNG': 
                        @list(/* RNG */, $sid, $server, /* auth_type */, $ticket, $email, $name, ) = @explode(' ', $data);
                        @list($sb_ip, $sb_port) = @explode(':', $server);
                        $this->helper->log("*** RING from $email, $sb_ip:$sb_port");
                        $this->switchboard_ring($sb_ip, $sb_port, $sid, $ticket, $email);
                        break;

                    case 'OUT': 
                        $this->helper->logoutError('Forced logout from NS');
                        break;


                    case 'ILN': 
                        $parsed = $this->protocol->parseILN( $data );
                        $this->contacts[ $parsed['email'] ] = $parsed;
                        break;

                    default:
                        $this->helper->log("*** IGNORE: ".$code.' | '.$data);

                }
            }

            foreach ( $this->switchboards as $key=>$val ) {
                $this->switchboards[$key]->doLoop($aParams);
            }

            if ($loopFunction && function_exists($loopFunction) && is_callable($loopFunction))
                $loopFunction($this);
        }
    } // end func

    function switchboard_ring($ip, $port, $sid, $ticket, $email)
    {
        $this->switchboards[] = new switchboard( $ip, $port, $sid, $ticket, $this, $email );
    } // end func    



} // end class
 
?>